home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / pcr / pcr4_4.lha / DIST / boot / CommandLine.c next >
C/C++ Source or Header  |  1990-11-06  |  25KB  |  1,038 lines

  1. /* begincopyright
  2.   Copyright (c) 1988 Xerox Corporation. All rights reserved.
  3.   Use and copying of this software and preparation of derivative works based
  4.   upon this software are permitted. Any distribution of this software or
  5.   derivative works must comply with all applicable United States export
  6.   control laws. This software is made available AS IS, and Xerox Corporation
  7.   makes no warranty about the software, its performance or its conformity to
  8.   any specification. Any person obtaining a copy of this software is requested
  9.   to send their name and post office or electronic mail address to
  10.   PCRCoordinator.pa@xerox.com, or to:
  11.     PCR Coordinator
  12.     Xerox PARC
  13.     3333 Coyote Hill Rd.
  14.     Palo Alto, CA 94304
  15.   endcopyright */
  16.  
  17. /*
  18.  * CommandLine.c
  19.  *
  20.  * PCR command line processing.
  21.  *
  22.  * Demers, November 6, 1990 11:22:42 am PST
  23.  */
  24.  
  25. #include "xr/CommandLine.h"
  26. #include "xr/CommandLinePrivate.h"
  27.  
  28. #include "xr/Threads.h"
  29. #include "xr/ThreadsBackdoor.h"
  30. #include "xr/ThreadsMsg.h"
  31. #include "xr/UIO.h"
  32.  
  33. #include <ctype.h>
  34.  
  35. /*
  36.  * Global data
  37.  */
  38.  
  39. struct XR_MLRep XR_globalCLLock;
  40.  
  41. #define LOCK() if( XR_currThread != NIL ) XR_MonitorEntry(&XR_globalCLLock)
  42. #define UNLOCK() if( XR_currThread != NIL ) XR_MonitorExit(&XR_globalCLLock)
  43.  
  44. /*
  45.  * Utilities ...
  46.  */
  47.  
  48. #define LOCKHANDLE(h)    if(XR_currThread != NIL ) \
  49.     XR_MonitorEntry( &(((XR_CLHandleInner)(h))->clh_ml) )
  50.  
  51. #define UNLOCKHANDLE(h)    if(XR_currThread != NIL ) \
  52.     XR_MonitorExit( &(((XR_CLHandleInner)(h))->clh_ml) )
  53.  
  54.  
  55.  
  56. static char *
  57. XR_CLNew(nBytes)
  58.     unsigned nBytes;
  59. {
  60.     char *ans;
  61.  
  62.     if( XR_currThread == NIL ) {
  63.         ans = ((char *)(XR_AllocSharedSysMem(nBytes)));
  64.     } else {
  65.         ans = ((char *)(XR_calloc(nBytes, 1)));
  66.     }
  67.     return ans;
  68. }
  69.  
  70.  
  71. /*
  72.     The following proc is part of newer C libraries ...
  73. */
  74.  
  75. bool
  76. strcmpcase(s1, s2)
  77.     char *s1;
  78.     char *s2;
  79. {
  80.     char c1, c2;
  81.  
  82.     for(;;) {
  83.         c1 = *s1++;  c2 = *s2++;
  84.         if( c1 == 0 ) {
  85.             return ((c1 < c2) ? (-1) : 0);
  86.         }
  87.         if( c1 != c2 ) {
  88.             if( islower(c1) && (c2 == toupper(c1)) ) continue;
  89.             if( isupper(c1) && (c2 == tolower(c1)) ) continue;
  90.             return ((c1 < c2) ? (-1) : 1);
  91.         }
  92.     }
  93. }
  94.  
  95.  
  96. static bool
  97. XR_CLStrEQ(s1, s2, caseSensitive)
  98.     char *s1;
  99.     char *s2;
  100.     bool caseSensitive;
  101. {
  102.     return ( (caseSensitive)
  103.             ? ( strcmp(s1, s2) == 0 )
  104.             : ( strcmpcase(s1, s2) == 0 ) );
  105. }
  106.  
  107.  
  108. /*
  109.  * Exported to CommandLine.h ...
  110.  */
  111.  
  112. XR_CLProcsHandle
  113. XR_CLCreateProcsHandle()
  114. {
  115.     XR_CLProcsHandleInner clph;
  116.  
  117.     clph = (XR_CLProcsHandleInner) XR_CLNew( sizeof *clph );
  118.     return ((XR_CLProcsHandle)(clph));
  119. }
  120.  
  121.  
  122. static XR_CLRegistrationInner
  123. XR_CLLookupRegistrationInternal(pH, key, caseSensitive)
  124.     XR_CLProcsHandle pH;
  125.     char *key;
  126.     bool caseSensitive;
  127. {
  128.     XR_CLProcsHandleInner clph = ((XR_CLProcsHandleInner)(pH));
  129.     XR_CLRegistrationInner clr;
  130.  
  131.     for( clr = clph->clph_registrations
  132.         ; (clr != NIL) && ( !XR_CLStrEQ(key, clr->clr_key,
  133.                 (caseSensitive && clr->clr_caseSensitive)) )
  134.         ; clr = clr->clr_next
  135.     ) { }
  136.     return clr;
  137. }
  138.  
  139.  
  140.  
  141.  
  142. XR_CLRegistration
  143. XR_CLRegisterProc(pH, key, caseSensitive, helpMsg, proc, replace)
  144.     XR_CLProcsHandle pH;
  145.     char *key;
  146.     bool caseSensitive;
  147.     char *helpMsg;
  148.     XR_MesaProc proc;
  149.     bool replace;
  150. {
  151.     XR_CLRegistrationInner rOld, rNew;
  152.  
  153.     if( (pH == NIL) || (proc == NIL) )
  154.         return NIL;
  155.     LOCK();
  156.     rOld = XR_CLLookupRegistrationInternal(pH, key, caseSensitive);
  157.     if( rOld == NIL ) {
  158.         rNew = ((XR_CLRegistrationInner)(XR_CLNew( sizeof *rNew )));
  159.         if( rNew != NIL ) {
  160.             rNew->clr_next = ((XR_CLProcsHandleInner)(pH))->clph_registrations;
  161.             ((XR_CLProcsHandleInner)(pH))->clph_registrations = rNew;
  162.         }
  163.     } else if( replace ) {
  164.         rNew = rOld;
  165.     } else {
  166.         rNew = NIL;
  167.     }
  168.     if( rNew != NIL ) {
  169.         rNew->clr_key = key;
  170.         rNew->clr_caseSensitive = caseSensitive;
  171.         rNew->clr_helpMsg = helpMsg;
  172.         rNew->clr_proc = proc;
  173.     }
  174.     UNLOCK();
  175.     return ((XR_CLRegistration)(rNew));
  176. }
  177.  
  178.  
  179.  
  180. int
  181. XR_CLUnsafeRegisterProcs(pH, description)
  182.     XR_CLProcsHandle pH;
  183.     char **description;
  184. {
  185.     XR_UntypedProc proc;
  186.     XR_Pointer data;
  187.     XR_MesaProc mProc;
  188.     char *help;
  189.     char *key;
  190.     XR_CLRegistration r;
  191.     char **desc;
  192.  
  193.     desc = description;
  194.     while( *desc ) {
  195.         proc = *((XR_UntypedProc *)(desc));  desc++;
  196.         data = *((XR_Pointer *)(desc));  desc++;
  197.         mProc = XR_MakeMesaProc(proc, data);
  198.         if( mProc == NIL ) return (-1);
  199.         help = *((char **)(desc));  desc++;
  200.         while( *desc ) {
  201.             key = *((char **)(desc));  desc++;
  202.             r = XR_CLRegisterProc( pH, key, FALSE, help, mProc, TRUE );
  203.             if( r == NIL ) return (-2);
  204.         }
  205.         desc++;
  206.     }
  207. }
  208.  
  209.  
  210. int
  211. XR_CLUnregister(pH, r)
  212.     XR_CLProcsHandle pH;
  213.     XR_CLRegistration r;
  214. {
  215.     XR_CLRegistrationInner ri, prev;
  216.  
  217.     if( pH == NIL ) return (-1);
  218.     LOCK();
  219.     ri = ((XR_CLProcsHandleInner)(pH))->clph_registrations;
  220.     prev = NIL;
  221.     while( ri != NIL ) {
  222.         if( ri == ((XR_CLRegistrationInner)(r)) ) {
  223.             if( prev == NIL ) {
  224.                 ((XR_CLProcsHandleInner)(pH))->clph_registrations
  225.                         = ri->clr_next;
  226.             } else {
  227.                 prev->clr_next = ri->clr_next;
  228.             }
  229.             break;
  230.         }
  231.         prev = ri;
  232.         ri = ri->clr_next;
  233.     }
  234.     UNLOCK();
  235.     return ((ri == ((XR_CLRegistrationInner)(r))) ? 0 : (-1));
  236. }
  237.  
  238.  
  239. XR_CLRegistration
  240. XR_CLGetRegistrationWithKey(pH, key)
  241.     XR_CLProcsHandle pH;
  242.     char *key;
  243. {
  244.     XR_CLRegistrationInner ans;
  245.  
  246.     if( pH == NIL ) return NIL;
  247.     LOCK();
  248.     ans = XR_CLLookupRegistrationInternal(pH, key, TRUE);
  249.     UNLOCK();
  250.     return ((XR_CLRegistration)(ans));
  251. }
  252.  
  253.  
  254. void
  255. XR_CLEnumerateRegistrations(pH, eachRegistration)
  256.     XR_CLProcsHandle pH;
  257.     XR_MesaProc eachRegistration;
  258. {
  259.     XR_CLRegistrationInner clr;
  260.     bool more;
  261.  
  262.     if( pH == NIL )
  263.         return;
  264.  
  265.     if( (eachRegistration == NIL) || (eachRegistration->mp_proc == NIL) )
  266.         return;
  267.  
  268.     LOCK();
  269.     clr = ((XR_CLProcsHandleInner)(pH))->clph_registrations;
  270.     while( clr != NIL ) {
  271.         more = (bool) ( (*(eachRegistration->mp_proc))(
  272.                 ((XR_CLRegistration)(clr)), eachRegistration ) );
  273.         if( !more ) break;
  274.         clr = clr->clr_next;
  275.     }
  276.     UNLOCK();
  277. }
  278.  
  279.  
  280. void
  281. XR_CLGetRegistrationDetails(r, key, caseSensitive, helpMsg, proc, clientData)
  282.     XR_CLRegistration r;
  283.     char **key;
  284.     bool *caseSensitive;
  285.     char **helpMsg;
  286.     XR_MesaProc *proc;
  287. {
  288.     XR_CLRegistrationInner clr;
  289.  
  290.     if( r == NIL ) return;
  291.     clr = ((XR_CLRegistrationInner)(r));
  292.     if( key != NIL ) *key = clr->clr_key;
  293.     if( caseSensitive != NIL ) *caseSensitive = clr->clr_caseSensitive;
  294.     if( helpMsg != NIL ) *helpMsg = clr->clr_helpMsg;
  295.     if( proc != NIL ) *proc = clr->clr_proc;
  296. }
  297.  
  298.  
  299. XR_MesaProc
  300. XR_CLGetProcForKey(pH, key)
  301.     XR_CLProcsHandle pH;
  302.     char *key;
  303. {
  304.     XR_CLRegistrationInner clr;
  305.     XR_MesaProc ans = NIL;
  306.  
  307.     if( pH == NIL ) return NIL;
  308.     LOCK();
  309.     clr = XR_CLLookupRegistrationInternal(pH, key, TRUE);
  310.     if( (clr == NIL) && (key[0] == '-') )
  311.         clr = XR_CLLookupRegistrationInternal(pH, &(key[1]), TRUE);
  312.     if( clr != NIL ) ans = clr->clr_proc;
  313.     UNLOCK();
  314.     return ans;
  315. }
  316.  
  317.  
  318. void
  319. XR_CLDestroyProcsHandle(pH)
  320.     XR_CLProcsHandle pH;
  321. {
  322. }
  323.  
  324.  
  325. /*
  326.  * Argument parsing
  327.  */
  328.  
  329.  
  330.  
  331. typedef unsigned XR_CLArgRes;
  332.  
  333. #define CL_ARG_RES_INL    1    /* inside-line */
  334. #define CL_ARG_RES_EOL    2    /* end-of-line */
  335. #define CL_ARG_RES_EOF    3    /* end-of-file */
  336. #define CL_ARG_RES_ERR    4    /* error */
  337.  
  338.  
  339. static void
  340. XR_CLDoPrompt(clh)
  341.     XR_CLHandleInner clh;
  342. {
  343.     XR_MesaProc promptSelf;
  344.     XR_UntypedProc promptProc;
  345.     char promptBuf[20];
  346.  
  347.     if( ((promptSelf = clh->clh_promptProc) != NIL)
  348.             && ((promptProc = promptSelf->mp_proc) != NIL) ) {
  349.         (void) XR_SPrintF( promptBuf,
  350.                 ((clh->clh_nestLevel > 0) ? "pcr(%d): " : "pcr: "),
  351.                 clh->clh_nestLevel );
  352.         (void)( (*promptProc)( promptBuf, strlen(promptBuf), promptSelf ) );
  353.     }
  354. }
  355.  
  356.  
  357. static XR_CLArgRes
  358. XR_CLReadArg(clh, buf, bufSize)
  359.     XR_CLHandleInner clh;
  360.     char *buf;
  361.     unsigned bufSize;
  362. {
  363.     char *to;
  364.     char *endp;
  365.     int c;
  366.     XR_MesaProc self;
  367.     XR_UntypedProc proc;
  368.  
  369.  
  370.     if( ((self = clh->clh_charProc) == NIL)
  371.             || ((proc = self->mp_proc) == NIL) )
  372.         return CL_ARG_RES_EOF;
  373.  
  374. #   define GETCHAR() ((int)( (*proc)(self) ))
  375.  
  376.     if( bufSize == 0 ) XR_Panic("CLReadArg 0");
  377.     to = buf;
  378.     endp = buf+bufSize-1;
  379.     c = clh->clh_peekc;
  380.     /* scan to beginning of token */
  381.     for(;;) {
  382.         if( c <= 0 ) { clh->clh_peekc = c; return CL_ARG_RES_EOF; }
  383.         if( c == '\n' ) {
  384.             XR_CLDoPrompt(clh);
  385.             if( (c = GETCHAR()) == '#' ) {
  386.                 /* comment */
  387.                 while( (c = GETCHAR()) != '\n' ) {
  388.                     if( c <= 0 ) { clh->clh_peekc = c; return CL_ARG_RES_EOF; }
  389.                 }
  390.             }
  391.             continue;
  392.         }
  393.         if( isspace(c) ) {
  394.             c = GETCHAR();
  395.             continue;
  396.         }
  397.         if( c == '\\' ) {
  398.             c = GETCHAR();
  399.             if( c <= 0 ) { clh->clh_peekc = c; return CL_ARG_RES_EOF; }
  400.             if( isspace(c) ) { c = ' '; continue; }
  401.             break;
  402.         }
  403.         break;
  404.     }
  405.     /* copy token to output buffer */
  406.     *to = c;  if( to < endp ) to++;
  407.     c = ( (c == '@') ? ' ' : (GETCHAR()) ); /* KLUDGE for "-@filename" */
  408.     for(;;) {
  409.         if( (c <= 0) || isspace(c) ) break;
  410.         if( c == '\\' ) {
  411.             c = GETCHAR();
  412.             if( c <= 0 ) break;
  413.         }
  414.         *to = c;  if( to < endp ) to++;
  415.         c = GETCHAR();
  416.     }
  417.     *to = 0;
  418.     /* check for eof/eol */
  419.     for(;;) {
  420.         clh->clh_peekc = c;
  421.         if( c <= 0 ) return CL_ARG_RES_EOL;
  422.             /* n.b. peekc will catch EOF on next call */
  423.         if( c == '\n' ) return CL_ARG_RES_EOL;
  424.         if( !isspace(c) ) return CL_ARG_RES_INL;
  425.         c = GETCHAR();
  426.     }
  427. }
  428. #undef GETCHAR
  429.  
  430.  
  431.  
  432. #define CL_INITIAL_ARGC_LIM 8
  433.  
  434. static int
  435. XR_CLGrowHandle(clh, howMuch)
  436.     XR_CLHandleInner clh;
  437.     unsigned howMuch; /* 0 ==> default */
  438. {
  439.     unsigned newArgcLim;
  440.     char **newArgv;
  441.  
  442.     if( clh == NIL ) return (-1);
  443.     if( howMuch == 0 ) {
  444.         howMuch = clh->clh_argcLim;
  445.         if( howMuch == 0 ) howMuch = CL_INITIAL_ARGC_LIM;
  446.     }
  447.     newArgcLim = clh->clh_argcLim + howMuch;
  448.     newArgv = (char **) XR_CLNew(newArgcLim * sizeof(char *));
  449.     if( newArgv == NIL ) return (-1);
  450.     if( clh->clh_argv != NIL ) {
  451.         bcopy(clh->clh_argv, newArgv, clh->clh_argcLim*sizeof(char *));
  452.     }
  453.     clh->clh_argv = newArgv;
  454.     clh->clh_argcLim = newArgcLim;
  455.     return 0;
  456. }
  457.  
  458.  
  459. #define CL_WORD_BUF_SIZE 256
  460.  
  461. static XR_CLArgRes
  462. XR_CLMakeArgAvailable(clh, argno)
  463.     XR_CLHandleInner clh;
  464.     int argno;
  465. {
  466.     XR_CLArgRes ans;
  467.     char *nextArg;
  468.     char wordBuf[CL_WORD_BUF_SIZE];
  469.  
  470.     if( argno < 0 ) XR_Panic("CLMakeArgAvailable 0");
  471.     if( argno < clh->clh_argc ) return CL_ARG_RES_INL;
  472.     ans = XR_CLReadArg(clh, wordBuf, (sizeof wordBuf));
  473.     switch( ans ) {
  474.         case CL_ARG_RES_INL:
  475.         case CL_ARG_RES_EOL:
  476.             nextArg = (char *) XR_CLNew(1+strlen(wordBuf));
  477.             (void) strcpy(nextArg, wordBuf);
  478.             if( clh->clh_argc >= clh->clh_argcLim ) XR_CLGrowHandle(clh, 0);
  479.             clh->clh_argv[clh->clh_argc] = nextArg;
  480.             clh->clh_argc += 1;
  481.             break;
  482.         case CL_ARG_RES_EOF:
  483.             break;
  484.         default:
  485.             XR_Panic("CLMakeArgAvailable 1");
  486.     }
  487.     return ans;
  488. }
  489.  
  490.  
  491. XR_CLHandle
  492. XR_CLCreateHandleFromCharProc(charProc, promptProc)
  493.     XR_MesaProc charProc;
  494.     XR_MesaProc promptProc;
  495. {
  496.     XR_CLHandleInner clh;
  497.  
  498.     clh = ((XR_CLHandleInner)(XR_CLNew(sizeof *clh)));
  499.     clh->clh_charProc = charProc;
  500.     clh->clh_peekc = '\n';
  501.     clh->clh_promptProc = promptProc;
  502.     return ((XR_CLHandle)(clh));
  503. }
  504.  
  505.  
  506. typedef struct XR_CLFileInfoRep {
  507.     XR_Fildes clfi_promptFildes;
  508.     XR_Fildes clfi_fildes;
  509.     bool clfi_eof;
  510.     unsigned clfi_pos;
  511.     unsigned clfi_lim;
  512.     char clfi_buf[256];
  513. } * XR_CLFileInfo;
  514.  
  515.  
  516. static int
  517. XR_CLBufferedCharProcForFile(self)
  518.     XR_MesaProc self;
  519. {
  520.     int ans;
  521.     XR_CLFileInfo clfi = ((XR_CLFileInfo)(self->mp_x));
  522.  
  523.     if( clfi->clfi_pos >= clfi->clfi_lim ) {
  524.         if( !(clfi->clfi_eof) ) {
  525.             ans = XR_Read(clfi->clfi_fildes, clfi->clfi_buf,
  526.                     (sizeof (clfi->clfi_buf)) );
  527.             if( ans > 0 ) {
  528.                 clfi->clfi_pos = 0;
  529.                 clfi->clfi_lim = ans;
  530.             } else {
  531.                 clfi->clfi_eof = TRUE;
  532.             }
  533.         }
  534.         if( clfi->clfi_eof ) return (-1);
  535.     }
  536.     ans = clfi->clfi_buf[clfi->clfi_pos];
  537.     clfi->clfi_pos += 1;
  538.     return ans;
  539. }
  540.  
  541. static int
  542. XR_CLUnbufferedCharProcForFile(self)
  543.     XR_MesaProc self;
  544. {
  545.     XR_CLFileInfo clfi = ((XR_CLFileInfo)(self->mp_x));
  546.     int ans;
  547.  
  548.     if( !clfi->clfi_eof ) {
  549.         ans = XR_Read(clfi->clfi_fildes, clfi->clfi_buf, 1);
  550.         clfi->clfi_eof = (ans <= 0);
  551.     }
  552.     return ((clfi->clfi_eof) ? (-1) : clfi->clfi_buf[0]);
  553. }
  554.  
  555.  
  556. static void
  557. XR_CLPromptProcForFile(buf, nBytes, self)
  558.     char *buf;
  559.     int nBytes;
  560.     XR_MesaProc self;
  561. {
  562.     XR_CLFileInfo clfi = ((XR_CLFileInfo)(self->mp_x));
  563.  
  564.     if( clfi->clfi_promptFildes != XR_nullFildes ) {
  565.         (void) XR_Write( clfi->clfi_promptFildes, buf, nBytes );
  566.     }
  567. }
  568.  
  569.  
  570. XR_CLHandle
  571. XR_CLCreateHandleFromFile(fd, fdPrompt)
  572.     XR_Fildes fd, fdPrompt;
  573. {
  574.     XR_CLFileInfo clfi;
  575.     XR_UntypedProc theCharProc, thePromptProc;
  576.     XR_CLHandle h;
  577.  
  578.     if( fd == XR_nullFildes ) return NIL;
  579.     clfi = (XR_CLFileInfo) XR_CLNew( sizeof *clfi );
  580.     if( clfi == NIL ) return NIL;
  581.     clfi->clfi_promptFildes = fdPrompt;
  582.     clfi->clfi_fildes = fd;
  583.     if( fdPrompt == XR_nullFildes ) {
  584.         theCharProc = ((XR_UntypedProc)(XR_CLBufferedCharProcForFile));
  585.         thePromptProc = NIL;
  586.     } else {
  587.         theCharProc = ((XR_UntypedProc)(XR_CLUnbufferedCharProcForFile));
  588.         thePromptProc = ((XR_UntypedProc)(XR_CLPromptProcForFile));
  589.     }
  590.     h = XR_CLCreateHandleFromCharProc(
  591.             XR_MakeMesaProc(
  592.                 theCharProc, ((XR_Pointer)(clfi))
  593.                 ),
  594.             XR_MakeMesaProc(
  595.                 thePromptProc, ((XR_Pointer)(clfi))
  596.                 )
  597.             );
  598.     return h;
  599. }
  600.  
  601.  
  602. typedef struct XR_CLStringInfoRep {
  603.     char *clsi_buf;
  604.     char *clsi_next;
  605. } * XR_CLStringInfo;
  606.  
  607.  
  608. static int
  609. XR_CLCharProcForString(self)
  610.     XR_MesaProc self;
  611. {
  612.     XR_CLStringInfo clsi = ((XR_CLStringInfo)(self->mp_x));
  613.     int ans;
  614.  
  615.     if( clsi == NIL ) return (-1);
  616.     if( clsi->clsi_next == NIL ) return (-1);
  617.     ans = ((int)(*(clsi->clsi_next)));
  618.     if( ans == 0 ) return (-1);
  619.     clsi->clsi_next += 1;
  620.     return ans;
  621. }
  622.  
  623.  
  624. XR_CLHandle
  625. XR_CLCreateHandleFromString(string)
  626.     char *string;
  627. {
  628.     char *s;
  629.     XR_CLStringInfo clsi;
  630.     XR_CLHandle h;
  631.  
  632.     s = (char *)XR_CLNew(1+strlen(string));
  633.     if( s == NIL ) return NIL;
  634.     strcpy(s, string);
  635.     clsi = (XR_CLStringInfo) XR_CLNew( sizeof (*clsi) );
  636.     if( clsi == NIL ) return NIL;
  637.     clsi->clsi_next = clsi->clsi_buf = s;
  638.     h = XR_CLCreateHandleFromCharProc(
  639.             XR_MakeMesaProc(
  640.                 (XR_UntypedProc)XR_CLCharProcForString, ((XR_Pointer)(clsi))
  641.                 ),
  642.             NIL
  643.             );
  644.     if( h != NIL ) {
  645.         ((XR_CLHandleInner)(h))->clh_minusIsDelim = TRUE;
  646.     }
  647.     return h;
  648. }
  649.  
  650.  
  651. XR_CLHandle
  652. XR_CLCreateHandleFromArgs(argc, argv)
  653.     int argc;
  654.     char **argv;
  655. {
  656.     XR_CLHandleInner clh;
  657.     char *newLineFlags = NIL;
  658.     int i;
  659.  
  660.     clh = ((XR_CLHandleInner)(XR_CLNew(sizeof *clh)));
  661.     if( clh == NIL ) return NIL;
  662.     clh->clh_minusIsDelim = TRUE;
  663.     clh->clh_argc = argc;
  664.     clh->clh_argcLim = argc;
  665.     clh->clh_argv = argv;
  666.     return ((XR_CLHandle)(clh));
  667. }
  668.  
  669.  
  670. int
  671. XR_CLPrependArgsToHandle(h, argc, argv)
  672.     XR_CLHandle h;
  673.     int argc;
  674.     char **argv;
  675. {
  676.     XR_CLHandleInner clh;
  677.     int i, ans, new_argc;
  678.  
  679.  
  680.     if( h == NIL ) return (-1);
  681.     if( argc == 0 ) return 0;
  682.     if( argv == NIL ) return (-1);
  683.  
  684.     clh = ((XR_CLHandleInner)(h));
  685.  
  686.     LOCKHANDLE(clh);
  687.  
  688.     new_argc = argc + clh->clh_argc;
  689.     if( clh->clh_argcLim < new_argc ) {
  690.         ans = XR_CLGrowHandle(clh, argc + (new_argc / 4));
  691.         if( ans < 0 ) {
  692.             UNLOCKHANDLE(clh);
  693.             return (-1);
  694.         }
  695.     }
  696.     for( i = clh->clh_argc - 1; i >= 0; i-- ) {
  697.         clh->clh_argv[i+argc] = clh->clh_argv[i];
  698.     }
  699.     for( i = 0; i < argc; i++ ) {
  700.         clh->clh_argv[i] = argv[i];
  701.     }
  702.     clh->clh_argc = new_argc;
  703.  
  704.     UNLOCKHANDLE(clh);
  705.     return 0;
  706. }
  707.  
  708.  
  709. void
  710. XR_CLDestroyHandle(h)
  711.     XR_CLHandle h;
  712. {
  713. }
  714.  
  715.  
  716.  
  717. static int
  718. XR_CLGetArgGroup(clh, start)
  719.     XR_CLHandleInner clh;
  720.     int start;
  721. {
  722.     int i, len;
  723.     XR_CLArgRes ans;
  724.     char *arg;
  725.  
  726.     for( i = start; ; i++ ) {
  727.         ans = XR_CLMakeArgAvailable(clh, i);
  728.         switch( ans ) {
  729.             case CL_ARG_RES_INL:
  730.             case CL_ARG_RES_EOL:
  731.                 arg = clh->clh_argv[i];
  732.                 if( arg[0] == '[' ) {
  733.                     clh->clh_nestLevel += 1;
  734.                 }
  735.                 if( (arg[0] == '-') && (i > start)
  736.                         && clh->clh_minusIsDelim
  737.                         && (clh->clh_nestLevel == 0) ) {
  738.                     return (i - start); 
  739.                 }
  740.                 if( clh->clh_nestLevel > 0) {
  741.                     len = strlen(arg);
  742.                     if( (len > 0) && (arg[len-1] == ']') )
  743.                         clh->clh_nestLevel -= 1;
  744.                 }
  745.                 if( (ans == CL_ARG_RES_EOL) && (clh->clh_nestLevel == 0) )
  746.                     return (i - start + 1);             
  747.                 continue;
  748.             case CL_ARG_RES_EOF:
  749.                 return (i - start);
  750.             default:
  751.                 XR_Panic("CLGetArgGroup 0");
  752.         }
  753.     }
  754. }
  755.  
  756.  
  757. int
  758. XR_CLApply(clce, preProc, postProc)
  759.     XR_CLCallEnv clce;
  760.     XR_MesaProc preProc;
  761.     XR_MesaProc postProc;
  762. {
  763.     XR_CLProcsHandleInner clph;
  764.     XR_CLHandleInner clh;
  765.     int start, i, argc;
  766.     XR_CLProc fixedPreProc, fixedPostProc;
  767.     XR_MesaProc handlerProc;
  768.     int (*fixedHandlerProc)(/* int prevResult, XR_MesaProc self */);
  769.     int ans = 1;
  770. #   define totalFailure 0x80000000
  771.  
  772.  
  773.     if( clce == NIL ) return (totalFailure);
  774.  
  775.     clph = ((XR_CLProcsHandleInner)(clce->clce_pH));
  776.     if( clph == NIL ) return (totalFailure);
  777.  
  778.     clh = ((XR_CLHandleInner)(clce->clce_h));
  779.     if( clh == NIL ) return (totalFailure);
  780.  
  781.     fixedPreProc =
  782.             ((preProc == NIL) ? NIL : ((XR_CLProc)(preProc->mp_proc)));
  783.     fixedPostProc =
  784.             ((postProc == NIL) ? NIL : ((XR_CLProc)(postProc->mp_proc)));
  785.  
  786.     LOCKHANDLE(clh);
  787.  
  788.     for( ((start = 0), (i = 0)); TRUE; ((start += argc), (i += 1)) ) {
  789.         argc = XR_CLGetArgGroup(clh, start);
  790.         if( argc <= 0 ) break;
  791.         {
  792.             XR_MesaProc proc;
  793.             XR_CLProc fixedProc;
  794.             int preProcResult, procResult, postProcResult;
  795.             int setjmpAns;
  796.  
  797.             /* invoke preProc */
  798.             preProcResult = 0;
  799.             if( fixedPreProc != NIL ) {
  800.                 preProcResult = (*fixedPreProc)(
  801.                         clce, argc, clh->clh_argv+start, 0, preProc );
  802.             }
  803.  
  804.             if( preProcResult > 0 ) continue;
  805.             if( preProcResult < 0 ) break;
  806.  
  807.             /* get and invoke registered CLProc */
  808.             procResult = 0;
  809.             proc = XR_CLGetProcForKey(
  810.                     (XR_CLProcsHandle)(clce->clce_pH),
  811.                     &((clh->clh_argv[start])[0]) );
  812.             if( proc != NIL ) {
  813.                 fixedProc = ((XR_CLProc)(proc->mp_proc));
  814.                 setjmpAns = XR_setjmp(&(clce->clce_jmpBuf));
  815.                 if( setjmpAns == 0 ) {
  816.                     procResult = (*fixedProc)(
  817.                             clce, argc, clh->clh_argv+start, 0, proc );
  818.                 } else /* proc aborted by longjmp */ {
  819.                     procResult = setjmpAns;
  820.                 }
  821.             }
  822.             
  823.             /* invoke postProc */
  824.             postProcResult = 1;
  825.             if( fixedPostProc != NIL ) {
  826.                 postProcResult = (*fixedPostProc)(
  827.                         clce, argc, clh->clh_argv+start, procResult, postProc );
  828.             }
  829.  
  830.             if( (ans = postProcResult) <= 0 ) {
  831.                 handlerProc = clce->clce_handlerProc;
  832.                 fixedHandlerProc =
  833.                         ((handlerProc == NIL)
  834.                             ? NIL
  835.                             : ((XR_CLProc)(handlerProc->mp_proc)));
  836.                 if( fixedHandlerProc != NIL ) {
  837.                     ans = (*fixedHandlerProc)(procResult, handlerProc);
  838.                 }
  839.                 if( ans <= 0 ) break;
  840.             }
  841.         }
  842.     }
  843.     UNLOCKHANDLE(clh);
  844.     return ans;
  845. }
  846.  
  847.  
  848. int
  849. XR_CLCallIndirect(clce, key, argc, argv)
  850.     XR_CLCallEnv clce;
  851.     char *key;
  852.     int argc;
  853.     char **argv;
  854. {
  855.     XR_MesaProc proc;
  856.     int ans;
  857.     struct XR_JmpBufRep prevJmpBuf;
  858.  
  859.     proc = XR_CLGetProcForKey( (XR_CLProcsHandle)(clce->clce_pH), key );
  860.     if( proc == NIL ) {
  861.         XR_CLErrorMsg "%s: %s not found\n",
  862.                 ((argc > 0) ? argv[0] : key), key );
  863.         return (-1);
  864.     }
  865.     (void) bcopy(&(clce->clce_jmpBuf), &prevJmpBuf, (sizeof prevJmpBuf));
  866.     if( (ans = XR_setjmp(&(clce->clce_jmpBuf))) == 0 ) {
  867.         ans = (int)( (*(proc->mp_proc)) (
  868.                 clce, argc, argv, 0, proc) );
  869.     }
  870.     (void) bcopy(&prevJmpBuf, &(clce->clce_jmpBuf), (sizeof prevJmpBuf));
  871.     return ans;
  872. }
  873.  
  874.  
  875. /*
  876.  *
  877.  * Utilities
  878.  *
  879.  */
  880.  
  881.  
  882. XR_CLPROC(XR_CLProc_setBool)
  883. {
  884.     bool isOn, wasOn;
  885.     XR_CLSetBoolProc onOffProc;
  886.  
  887.     switch( argc ) {
  888.         case 2:
  889.             if( (strcmp(argv[1], "on") == 0)
  890.                     || (strcmp(argv[1], "true") == 0)
  891.                     || (strcmp(argv[1], "ON") == 0)
  892.                     || (strcmp(argv[1], "TRUE") == 0) ) {
  893.                 isOn = TRUE;
  894.                 break;
  895.             }
  896.             if( (strcmp(argv[1], "off") == 0)
  897.                     || (strcmp(argv[1], "false") == 0)
  898.                     || (strcmp(argv[1], "OFF") == 0)
  899.                     || (strcmp(argv[1], "FALSE") == 0) ) {
  900.                 isOn = FALSE;
  901.                 break;
  902.             }
  903.         default:
  904.             XR_CLErrorMsg "%s args: [on|off]\n", argv[0]);
  905.             return (-1);
  906.     }
  907.     onOffProc = (XR_CLSetBoolProc)(self->mp_x);
  908.     wasOn = (*onOffProc)(isOn);
  909.     XR_CLNormalMsg "%s set %s (was %s)\n",
  910.             argv[0], (isOn ? "on" : "off"), (wasOn ? "on" : "off") );
  911.     return 1;
  912. }
  913.  
  914.  
  915.  
  916. XR_CLPROC(XR_CLProc_setUnsigned)
  917. {
  918.     unsigned newNum, oldNum;
  919.     XR_CLSetUnsignedProc numberProc;
  920.  
  921.     switch( argc ) {
  922.         case 2:
  923.             newNum = atol(argv[1]);
  924.             break;
  925.         default:
  926.             XR_CLErrorMsg "%s args: number\n", argv[0]);
  927.             return (-1);
  928.     }
  929.     numberProc = (XR_CLSetUnsignedProc)(self->mp_x);
  930.     oldNum = (*numberProc)(newNum);
  931.     XR_CLNormalMsg "%s set to %d (was %d)\n", argv[0], newNum, oldNum );
  932.     return 1;
  933. }
  934.  
  935.  
  936.  
  937. #ifdef UNDEFINED
  938. /*
  939.  * DEBUGGING PROCS
  940.  */
  941.  
  942. XR_CLHandle
  943. XR_CLDBCreate(argc, argv0, argv1, argv2, argv3, argv4, argv5, argv6, argv7)
  944.     int argc;
  945.     char *argv0;
  946.     char *argv1;
  947.     char *argv2;
  948.     char *argv3;
  949.     char *argv4;
  950.     char *argv5;
  951.     char *argv6;
  952.     char *argv7;
  953. {
  954.     char **argv;
  955.  
  956.     if( (argc <= 0) || (argc > 8) ) return NIL;
  957.     argv = (char **)(XR_malloc(argc*sizeof(char *)));
  958.     if( argc > 0 ) argv[0] = argv0;
  959.     if( argc > 1 ) argv[1] = argv1;
  960.     if( argc > 2 ) argv[2] = argv2;
  961.     if( argc > 3 ) argv[3] = argv3;
  962.     if( argc > 4 ) argv[4] = argv4;
  963.     if( argc > 5 ) argv[5] = argv5;
  964.     if( argc > 6 ) argv[6] = argv6;
  965.     if( argc > 7 ) argv[7] = argv7;
  966.     return XR_CLCreateHandleFromArgs(argc, argv, NIL);
  967. }
  968.  
  969.  
  970. #define MSG XR_Msg(XR_MSG_STDOUT,
  971.  
  972. XR_CLPROC(XR_CLDBProc)
  973. {
  974.     int i;
  975.  
  976.     MSG "CLDBProc_%s called: pr %d which %d clce 0x%x args ",
  977.             prevResult, which, clce, self->mp_x);
  978.     for( i = 0; i < argc; i++ ) {
  979.         MSG "%s ", argv[i]);
  980.     }
  981.     return 1;
  982. }
  983.  
  984.  
  985. struct XR_MesaProcRep XR_CLDBMProc_preProc = {
  986.     (XR_UntypedProc)(XR_CLDBProc), (XR_Pointer)("preProc") };
  987.  
  988. struct XR_MesaProcRep XR_CLDBMProc_postProc = {
  989.     (XR_UntypedProc)(XR_CLDBProc), (XR_Pointer)("postProc") };
  990.  
  991. struct XR_MesaProcRep XR_CLDBMProc_regProc = {
  992.     (XR_UntypedProc)(XR_CLDBProc), (XR_Pointer)("regProc") };
  993.  
  994.  
  995. int
  996. XR_CLDBReadFile(fileName, pH, msgSink, verbosity, preProc, postProc)
  997.     char *fileName;
  998.     XR_CLProcsHandle pH;
  999.     XR_MesaProc msgSink;
  1000.     int verbosity;
  1001.     XR_MesaProc preProc;
  1002.     XR_MesaProc postProc;
  1003. {
  1004.     XR_Fildes fd;
  1005.     struct XR_CLCallEnvRep clce;
  1006.     XR_CLHandle h;
  1007.     int ans;
  1008.     int localVerbosity = verbosity;
  1009.  
  1010.     fd = XR_Open(fileName, O_RDONLY, 0);
  1011.     if( fd == XR_nullFildes ) return (-1);
  1012.     (void) XR_SetGetBlocking(fd, XR_UIO_BLOCKING_SOME_DATA); /* default */
  1013.     h = XR_CLCreateHandleFromFile(fd);
  1014.     clce.clce_h = h;
  1015.     clce.clce_pH = pH;
  1016.     clce.clce_msgSink = msgSink;
  1017.     clce.clce_msgVerbosityP = &localVerbosity;
  1018.     clce.clce_handlerProc = NIL;
  1019.     clce.clce_clientData = NIL;
  1020.     ans = XR_CLApply( &clce, preProc, postProc );
  1021.     (void) XR_Close(fd);
  1022.     return ans;
  1023. }
  1024.  
  1025. #endif UNDEFINED
  1026.  
  1027. XR_PrintArgV(argv, start, limit)
  1028.     char **argv;
  1029.     int start, limit;
  1030. {
  1031.     while( start < limit ) {
  1032.         XR_ConsoleMsg("  %d: %s\n", start, argv[start]);
  1033.         XR_SpinStep(50000);
  1034.         start += 1;
  1035.     }
  1036. }
  1037.  
  1038.